use actix::prelude::*;
use actix_files::Files;
use actix_session::{storage::CookieSessionStore, SessionMiddleware};
use actix_web::cookie::Key;
use actix_web::web::Data;
use actix_web::{web, App, HttpServer};

use super::account;
use super::auth;
use super::ipc;
use super::login;
use crate::config::Config;
use crate::my_actor;
use crate::service;
use std::io;
use std::sync::Arc;
use tokio::task;

use log::info;

pub struct Server {}

impl Server {
    pub fn new() -> Self {
        Server {}
    }

    pub async fn start(&self) -> io::Result<()> {
        let config = Config::new();
        let bind = format!("{}:{}", config.http.host, config.http.port);
        let root_dir = config.http.root.clone();

        info!("Listening on http://{}", bind);

        let addr = my_actor::MyActor::new().start();
        let addr_arc = Arc::new(addr);

        let service = service::Service::new();
        let service_arc = Arc::new(service);

        // 启动上一次非正常结束的推流任务
        task::spawn(service::start::start_undone(
            service_arc.clone(),
            addr_arc.clone(),
        ));
        // 定时检查 异常终止任务，并重试
        task::spawn(service::start::retry_abnormal(
            config,
            service_arc.clone(),
            addr_arc.clone(),
        ));

        // 定时检查 状态检查
        task::spawn(service::start::status_check(service_arc.clone()));

        HttpServer::new(move || {
            App::new()
                .wrap(
                    SessionMiddleware::builder(CookieSessionStore::default(), Key::from(&[0; 64]))
                        .cookie_secure(false)
                        .build(),
                )
                .wrap(auth::Auth(service_arc.clone()))
                .app_data(Data::new(service_arc.clone()))
                .app_data(Data::new(addr_arc.clone()))
                .service(web::resource("/api/login").route(web::post().to(login::login)))
                .service(web::resource("/api/ipc").route(web::post().to(ipc::add_ipc)))
                .service(web::resource("/api/ipc").route(web::put().to(ipc::update_ipc)))
                .service(web::resource("/api/ipc/{id}").route(web::delete().to(ipc::delete_ipc)))
                .service(web::resource("/api/ipcs").route(web::get().to(ipc::get_ipc_list)))
                .service(web::resource("/api/ipc/{id}").route(web::get().to(ipc::get_ipc)))
                .service(
                    web::resource("/api/ipc/{id}/start")
                        .route(web::get().to(ipc::ipc_publish_start)),
                )
                .service(
                    web::resource("/api/ipc/{id}/stop").route(web::get().to(ipc::ipc_publish_stop)),
                )
                .service(web::resource("/api/ipcs/num").route(web::get().to(ipc::get_ip_num)))
                .service(web::resource("/api/ipc/key/gen").route(web::get().to(ipc::gen_key)))
                .service(
                    web::resource("/api/change-password")
                        .route(web::post().to(account::change_password)),
                )
                .service(
                    Files::new("/", &root_dir)
                        .prefer_utf8(true)
                        .index_file("index.html"),
                )
        })
        .bind(bind)?
        .run()
        .await
    }
}
